package com.graduation_design.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.graduation_design.common.dto.SysMenuDto;
import com.graduation_design.entity.SysMenu;
import com.graduation_design.entity.SysRoleMenu;
import com.graduation_design.modules.system.shiro.AccountProfile;
import com.graduation_design.service.SysMenuService;
import com.graduation_design.mapper.SysMenuMapper;
import com.graduation_design.service.SysRoleMenuService;
import com.graduation_design.utils.ShiroUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author 从南
* @description 针对表【sys_menu】的数据库操作Service实现
* @createDate 2024-02-16 18:15:59
*/
@Slf4j
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu>
    implements SysMenuService{

    @Resource
    SysMenuMapper sysMenuMapper;

    @Resource
    SysRoleMenuService sysRoleMenuService;

    /**
     * 通过中间表获取用户关联的菜单列表，需要注意的是当用户Id为1的时候，
     * 表示当前用户是超级管理员admin，是可以获取所有菜单列表的。
     */
    @Override
    public List<SysMenu> listMenusByUserId(Long userId) {

        // 用户id为1的超级管理员

        // 管理员 角色 菜单
        List<Long> menuIds = sysMenuMapper.getMenuIdsByUserId(userId);
        if (userId != 1 && menuIds.size() == 0) {
            // 没有任何菜单
            return new ArrayList<>();
        }

        return this.list(new QueryWrapper<SysMenu>()
                .in(userId != 1, "id", menuIds) // 1是超级管理员admin，可以管理所有菜单
                .eq("status", 0)
                .orderByDesc("sort_order")
        );
    }

    @Override
    public List<SysMenuDto> getCurrentUserNav() {
        // 通过sys_user_role与sys_role_menu连接后通过userId来获取用户关联的menuIds
        AccountProfile profile = ShiroUtil.getProfile();
        
        List<SysMenu> menus = this.listMenusByUserId(profile.getId());

        // 通过parendId关联树形结构的上下级关系，最后按照一定格式返回
        List<SysMenu> sysMenus = buildTreeMenu(menus);

        return BeanUtil.copyToList(sysMenus, SysMenuDto.class);
    }

    /**
     * 获取当前用户菜单的权限列表
     * 在获取菜单列表的基础上，把菜单所代表的权限码提出来
     */
    @Override
    public String getUserPerms(Long userId) {

        // 结果例子：sys:user:save，只要权限码，不包括角色
        List<SysMenu> menus = this.listMenusByUserId(userId);
        String perms = menus.stream().map(SysMenu::getPerms).collect(Collectors.joining(","));

        log.info("用户ID - {} ---拥有的权限：{}", userId, perms);
        return perms;
    }

    /**
     * 获取菜单，然后构建树形结构
     */
    @Override
    public List<SysMenu> tree() {

        List<SysMenu> menus = this.list(new QueryWrapper<SysMenu>()
//                .eq("status", 0)
                .orderByDesc("sort_order")
        );
        return buildTreeMenu(menus);
    }

    /**
     * 在删除当前的菜单之前需要先判断是否有子菜单，如果有子菜单是不允许直接删除的，避免误操作。
     * 然后当前菜单的关联表的信息也要对应删除。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {

        // 判断是否有子级
        long count = this.count(new QueryWrapper<SysMenu>().eq("parent_id", id));
        Assert.isTrue(count < 1, "请先删除子菜单");

        removeById(id);

        // 同步删除roleMenu中间表的记录
        sysRoleMenuService.remove(new QueryWrapper<SysRoleMenu>().eq("menu_id", id));
    }

    /**
     * 把list转成树形结构的数据
     */
    private List<SysMenu> buildTreeMenu(List<SysMenu> menus) {
        List<SysMenu> finalMenus = new ArrayList<>();
        for (SysMenu menu : menus) {
            // 先寻找各自的孩子
            for (SysMenu e : menus) {
                if (e.getParentId() == menu.getId().longValue()) {
                    menu.getChildren().add(e);
                }
            }
            // 提取出父节点
            if (menu.getParentId() == 0L) {
                finalMenus.add(menu);
            }
        }
        return finalMenus;
    }
}




